package com.binance.rabbitmq.config;

import com.binance.rabbitmq.exception.RabbitmqConfigurationException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Singular;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Created by robin.wu on 2018/11/29.
 */
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
@Log4j2
@ConfigurationProperties(prefix = "rabbitmq.auto-config")
public class RabbitConfig {
    /** 可配置消息头 **/
    @Singular
    private Map<String, Object> infoHeaders = new LinkedHashMap<>();

    @Singular("exchange")
    private Map<String, ExchangeConfig> exchanges = new LinkedHashMap<>();

    @Singular("queue")
    private Map<String, QueueConfig> queues = new LinkedHashMap<>();

    @Singular("binding")
    private Map<String, BindingConfig> bindings = new LinkedHashMap<>();


    @Autowired
    private DefaultConfig defaultConfig;

    @PostConstruct
    public void validate() {
        boolean valid = true;
        log.info("Validating exchange...");
        for (Map.Entry<String, ExchangeConfig> entry : exchanges.entrySet()) {
            valid = validate(entry.getKey(), entry.getValue(), valid);
        }
        log.info("Validating queue...");
        for (Map.Entry<String, QueueConfig> entry : queues.entrySet()) {
            valid = validate(entry.getKey(), entry.getValue(), valid);
        }
        log.info("Validating binding...");
        for (Map.Entry<String, BindingConfig> entry : bindings.entrySet()) {
            valid = validate(entry.getKey(), entry.getValue(), valid);
        }

        if (isDeadLetterEnabled()) {
            log.info("Validating DeadLetterConfig...");
            if (defaultConfig.getDeadLetterConfig() == null || defaultConfig.getDeadLetterConfig().getDeadLetterExchange() == null) {
                log.error("Validating failed. DeadLetterConfig must provided if any queue enable dead letter queue.");
                valid = false;
            } else {
                valid = validate("DeadLetterConfig", defaultConfig.getDeadLetterConfig(), valid);
            }
        }

        if (valid) {
            log.info("RabbitConfig Validation done successfully. RabbitConfig = {{}}", this.toString());
        } else {
            throw new RabbitmqConfigurationException("Invalid RabbitConfig Configuration");
        }
    }

    private boolean validate(String key, AbstractConfig abstractConfig, boolean valid) {
        log.info("Validating key {} :: value {}...", key, abstractConfig);
        return abstractConfig.validate() ? valid : false;
    }


    private boolean isDeadLetterEnabled() {
        if (defaultConfig.getDefaultQueue() != null && defaultConfig.getDefaultQueue().getDeadLetterEnabled() != null && defaultConfig.getDefaultQueue().getDeadLetterEnabled()) {
            return true;
        } else {
            for (QueueConfig currentQueue : queues.values()) {
                if (currentQueue.getDeadLetterEnabled() != null && currentQueue.getDeadLetterEnabled()) {
                    return true;
                }
            }
            return false;
        }
    }
}
